/* Copyright 2001,2002,2003 NAH6 BV
 * All Rights Reserved
 *
 *  $Header: /var/lib/cvs/secphone/ui/crypto/CryptProvider.cpp,v 1.4 2003/11/21 12:39:24 itsme Exp $
 *
 *
 *  wrapper around MS CryptoApi.
 *
 *  used to generate/verify license, and sign xip update blocks.
 *
 */

#include <windows.h>
#include <wincrypt.h>
#include "debug.h"
#include "stringutils.h"
#include "vectorutils.h"

#include "CryptProvider.h"

CryptProvider::CryptProvider()
{
    m_hProv= NULL;
}
CryptProvider::~CryptProvider()
{
    if (m_hProv)
        Close();
}

bool CryptProvider::Open()
{
    if (!CryptAcquireContext(&m_hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
    {
        error("CryptAcquireContext");
        m_hProv= NULL;
        return false;
    }

    return true;
}
bool CryptProvider::Close()
{
    if (m_hHash) {
        CryptDestroyHash(m_hHash);
        m_hHash= NULL;
    }
    if (m_hKey) {
        CryptDestroyKey(m_hKey);
        m_hKey= NULL;
    }
    CryptReleaseContext(m_hProv, 0);
    m_hProv= NULL;
    return true;
}

bool CryptProvider::GenerateKey(int keyLength)
{
    if(!CryptGenKey(m_hProv, CALG_RSA_SIGN,  (keyLength<<16) | CRYPT_EXPORTABLE, &m_hKey))
    {
        error("CryptGenKey");
        return false;
    } 
    return true;
}

bool CryptProvider::GetPrivateKey(ByteVector& keydata)
{
    DWORD len=0;
    if (!CryptExportKey(m_hKey, NULL, PRIVATEKEYBLOB, 0, NULL, &len))
    {
        if (GetLastError()!=ERROR_MORE_DATA) {
            error("CryptExportKey");
            return false;
        }
    }
    keydata.resize(len);
    if (!CryptExportKey(m_hKey, NULL, PRIVATEKEYBLOB, 0, vectorptr(keydata), &len))
    {
        error("CryptExportKey");
        return false;
    }

    return true;
}

bool CryptProvider::SetPrivateKey(const ByteVector& keydata)
{
    if (!CryptImportKey(m_hProv, vectorptr(keydata), keydata.size(), 0, CRYPT_EXPORTABLE, &m_hKey))
    {
        error("CryptImportKey(%d)", keydata.size());
        return false;
    }

    return true;
}
bool CryptProvider::SetPublicKey(const ByteVector& keydata)
{
    if (!CryptImportKey(m_hProv, vectorptr(keydata), keydata.size(), 0, 0, &m_hKey))
    {
        error("CryptImportKey(%d)", keydata.size());
        return false;
    }

    return true;
}

bool CryptProvider::GetPublicKey(ByteVector& keydata)
{
    DWORD len=0;
    if (!CryptExportKey(m_hKey, NULL, PUBLICKEYBLOB, 0, NULL, &len))
    {
        if (GetLastError()!=ERROR_MORE_DATA) {
            error("CryptExportKey");
            return false;
        }
    }
    keydata.resize(len);
    if (!CryptExportKey(m_hKey, NULL, PUBLICKEYBLOB, 0, vectorptr(keydata), &len))
    {
        error("CryptExportKey");
        return false;
    }
    return true;
}

bool CryptProvider::CalculateAndSignHash(const ByteVector& data, ByteVector& signature)
{
    if (!CryptCreateHash(m_hProv, CALG_MD5, 0, 0, &m_hHash))
    {
        error("CryptCreateHash");
        return false;
    }
    if (!CryptHashData(m_hHash, vectorptr(data), data.size(), 0))
    {
        error("CryptHashData");
        return false;
    }
    // calculate signature
    DWORD siglen;
    if (!CryptSignHash(m_hHash, AT_SIGNATURE, NULL, 0, NULL, &siglen))
    {
        error("CryptSignHash");
        return false;
    }
    signature.resize(siglen);
    if (!CryptSignHash(m_hHash, AT_SIGNATURE, NULL, 0, vectorptr(signature), &siglen))
    {
        error("CryptSignHash");
        return false;
    }

    CryptDestroyHash(m_hHash);
    m_hHash= NULL;

    return true;
}
bool CryptProvider::CalculateAndVerifyHash(const ByteVector& data, const ByteVector& signature)
{
    if (!CryptCreateHash(m_hProv, CALG_MD5, 0, 0, &m_hHash))
    {
        error("CryptCreateHash");
        return false;
    }
    if (!CryptHashData(m_hHash, vectorptr(data), data.size(), 0))
    {
        error("CryptHashData");
        return false;
    }
    // calculate signature
    if (!CryptVerifySignature(m_hHash, vectorptr(signature), signature.size(), m_hKey, NULL, 0))
    {
        error("CryptVerifySignature");
        return false;
    }
    CryptDestroyHash(m_hHash);
    m_hHash= NULL;

    return true;
}


bool CryptProvider::GenerateRandomData(ByteVector& data, int size)
{
    data.resize(size);
    if (!CryptGenRandom(m_hProv, data.size(), vectorptr(data)))
    {
        error("getting random data\n");
        return false;
    }
    return true;
}

